﻿namespace Core.Business.Domain.Entities {
    using System.Collections.Generic;
    using VfbSharp.Validations;
    using Core.Business.Domain.Exceptions;
    using System.Linq;
    using System;

    public abstract class Conta {
        public virtual long Id { get; set; }
        public virtual string Descricao { get; set; }
        public virtual string Banco { get; set; }
        public virtual TipoConta Tipo { get; protected set; }
        public virtual IList<Lancamento> Lancamentos { get; private set; }

        protected Conta() { }
        protected Conta(string descricao, string banco) {
            this.Descricao = descricao;
        }

        public virtual void AddAgendamento(int totalLancamentos, string comentario, DateTime inicio, TipoLancamento tipo, Favorecido favorecido, double valor, Frequencia frequencia) {            

            for (int i = 0; i < totalLancamentos; i++) {
                var parcela = new Parcela(i + 1, totalLancamentos);
                var dataLancamento = GetFrequencia(inicio, i, frequencia);

                var lancamento = Lancamento.GetLancamento(valor, comentario, favorecido, TipoSituacao.ABERTO, dataLancamento, tipo, parcela);

                AddLancamento(lancamento);
            }
        }

        public virtual DateTime GetFrequencia(DateTime data, int acrescimo, Frequencia frequencia){

            if (frequencia == Frequencia.MENSAL)
                return data.AddMonths(acrescimo);

            if (frequencia == Frequencia.ANUAL)
                return data.AddYears(acrescimo);

            return data.AddDays(acrescimo);
        }

        public virtual void AddLancamento(Lancamento lancamento) {
            if (lancamento.IsNull()) throw new BusinessException("Lançamento inválido!");

            Lancamentos = Lancamentos ?? new List<Lancamento>();
            lancamento.Conta = this;
            Lancamentos.Add(lancamento);
        }

        public virtual double GetSaldo() { 
            this.Lancamentos = this.Lancamentos ?? new List<Lancamento>();

            return this.Lancamentos.Where(l => l.Situacao == TipoSituacao.CONSOLIDADO)
                                   .Sum(l => l.Valor);
        }

        public virtual double GetRendimentos() {
            this.Lancamentos = this.Lancamentos ?? new List<Lancamento>();

            return this.Lancamentos.Where(l => l.Tipo == TipoLancamento.DEPOSITO)
                                   .Where(l => l.Situacao == TipoSituacao.CONSOLIDADO)
                                   .Sum(l => l.Valor);
        }

        public virtual double GetDespesas() {
            this.Lancamentos = this.Lancamentos ?? new List<Lancamento>();

            return this.Lancamentos.Where(l => l.Tipo == TipoLancamento.SAQUE)
                                   .Where(l => l.Situacao == TipoSituacao.CONSOLIDADO)
                                   .Sum(l => l.Valor);
        }

        public override bool Equals(object obj){
            var toCompare = obj as Conta;

            if (toCompare.IsNull())
                return false;

            if (toCompare.Id == this.Id && toCompare.Id == this.Id)
                return true;
            return false;
        }

        public override int GetHashCode() {
            return Id.GetHashCode();
        }

        public static C GetConta<C>(string descricao, string banco) where C : Conta {

            var conta = (C)Activator.CreateInstance(typeof(C), true);
            conta.Descricao = descricao;
            conta.Banco = banco;

            return conta;
        }
    }
}